package com.mallcai.bigdata.ladon.service.report.node;



import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author feixy
 * @version 1.0
 * @date 2019-08-03 21:01
 */
public class ReportSqlNodeUtils {

    public static final String IF_TAG_NAME= "IF";
    public static final String EXP1_TAG_NAME= "EXP1";
    public static final String EXP2_TAG_NAME= "EXP2";
    public static final String OP_TAG_NAME= "OP";
    public static final String TEXT_TAG_NAME= "TEXT";
    public static final String ELSE_TEXT_TAG_NAME= "ELSETEXT";
    public static final Pattern IF_PATTERN = Pattern.compile("(</?IF>)",Pattern.CASE_INSENSITIVE);

    /**
     * 根据标签名分割
     * @param sql
     * @return
     */
    public static List<String> splitByIfTag(String sql){
        Matcher matcher = IF_PATTERN.matcher(sql);
        List<String> ans = new ArrayList<>();
        Stack<Integer /*<if> start index*/> stack = new Stack<>();
        int matchStart = 0;
        int matchEnd = 0;
        int lastMatchEnd = matchEnd;
        while (matcher.find()){
            String tag = matcher.group(1);
            matchStart = matcher.start();
            matchEnd = matcher.end();
            if (tag.indexOf("/") == -1){
                // 加上第一个匹配标签的前面的内容
                if (matchStart > 0 && stack.isEmpty() && (matchStart > (lastMatchEnd+1)) ){
                    ans.add(sql.substring(lastMatchEnd, matchStart));
                }
                stack.push(matchStart);
            } else {
                if (stack.isEmpty()){
                    throw new SqlNodeParseException("动态sql解析出错,存在非法的</IF>标签, sql:%s", sql);
                }
                Integer pop = stack.pop();
                if(stack.isEmpty()){
                    ans.add(sql.substring(pop, matchEnd));
                }
            }
            lastMatchEnd = matchEnd;
        }
        if (!stack.isEmpty()){
            throw new SqlNodeParseException("动态sql解析出错,存在非法的<IF>标签, sql:%s", sql);
        }
        if (lastMatchEnd < sql.length()){
            ans.add(sql.substring(lastMatchEnd));
        }
        return ans;
    }

    /**
     * 从content中抽取出第一个tag标签的内容(该方法会处理嵌套标签问题)
     * @param content
     * @param tagName
     * @param withTag: 返回值是否包含开始和结束的标签名
     * @return
     */
    private static Optional<String> extractValue(String content, String tagName, boolean withTag){
        String openTag = getOpenTagName(tagName);
        String closeTag = getCloseTagName(tagName);
        Pattern pattern = Pattern.compile(String.format("(</?%s>)",tagName),Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(content);
        Stack<Integer> stack = new Stack<>();
        int matchStart = 0;
        int matchEnd = 0;
        while (matcher.find()){
            String tag = matcher.group(1);
            matchStart = matcher.start();
            matchEnd = matcher.end();
            if (tag.equalsIgnoreCase(openTag)){
                stack.push(matchStart);
            } else {
                int start = stack.pop();
                if(stack.isEmpty()){
                    int end = matchEnd;
                    if(!withTag){
                        start += openTag.length();
                        end -= closeTag.length();
                    }
                    return Optional.of(content.substring(start, end));
                }
            }
        }
        return Optional.empty();
    }

    /**
     * 从content中抽取出第一个tag标签的内容,返回值包含标签的内容
     * @param content
     * @param tagName
     * @return
     */
    public static Optional<String> extractValueWithTag(String content, String tagName){
        return extractValue(content, tagName, true);
    }

    /**
     * 从content中抽取出第一个tag标签的内容,返回值不包含标签的内容
     * @param content
     * @param tagName
     * @return
     */
    public static Optional<String> extractValueOnly(String content, String tagName){
        return extractValue(content, tagName, false);
    }


    private static String getOpenTagName(String tagName){
        return getTagName(tagName, true);
    }

    private static String getCloseTagName(String tagName){
        return getTagName(tagName, false);
    }

    private static String getTagName(String tagName, boolean isOpen){
        return String.format("<%s%s>", isOpen?"":"/", tagName);
    }

}
